package com.study.concurrent.C_ThreadSynchronizationHelperClass.h_RunningOfConcurrentPhaseTasks;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;

/**
 * Created by 赵超 on 2017/3/26.
 * 文件查找类
 */
public class FileSearch implements Runnable {
    private String initPath; // 存储待查找的文件夹目录
    private String end; // 存储待查找文件的扩展名
    private List<String> results; // 存储查找到的文件的完整路径
    private Phaser phaser; // 控制任务不同阶段的同步

    public FileSearch(String initPath, String end, Phaser phaser) {
        this.initPath = initPath;
        this.end = end;
        this.phaser = phaser;
        this.results = new ArrayList<>();
    }

    /**
     * 遍历出查找文件夹中的所有文件并传入fileProcess()方法
     *
     * @param file 文件夹目录
     */
    private void directoryProcess(File file) {
        File[] files = file.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if (files[i].isDirectory()) {
                    // 如果是文件夹就递归调用查找里面的文件
                    directoryProcess(files[i]);
                } else {
                    // 如果是文件就传入方法检查文件扩展名（后缀）是否为指定扩展名
                    fileProcess(files[i]);
                }
            }
        }
    }

    /**
     * 检查文件的扩展名（后缀）是否为指定扩展名，如果是，就将文件的绝对路径放入results集合中
     *
     * @param file 文件对象
     */
    private void fileProcess(File file) {
        if (file.getName().endsWith(end)) {
            results.add(file.getAbsolutePath());
        }
    }

    /**
     * 文件过滤，过滤掉24小时之前修改的文件
     */
    private void filterResults() {
        ArrayList<String> newResults = new ArrayList<>();
        long nowTime = new Date().getTime();
        for (int i = 0; i < results.size(); i++) {
            File file = new File(results.get(i));
            long lastModifiedTime = file.lastModified();
            // 校验文件最后修改时间是否超过24小时
            if (nowTime - lastModifiedTime <
                    TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS)) {
                newResults.add(results.get(i));
            }
        }
        results = newResults; // 将新的结果集引用赋给results
    }

    /**
     * 检查结果列表的长度
     *
     * @return 结果不为空返回true，否则返回false
     */
    private boolean checkResults() {
        if (results.isEmpty()) {
            System.out.printf("%s : Phase %d: 0 条记录符合要求. \n",
                    Thread.currentThread().getName(), phaser.getPhase());
            System.out.printf("%s : Phase %d: 结束执行.\n",
                    Thread.currentThread().getName(), phaser.getPhase());
            phaser.arriveAndDeregister(); // 通知Phaser对象当前线程已经结束这个阶段，并且将不会参与接下来的阶段操作
            return false;
        } else {
            System.out.printf("%s : Phase %d: 共有 %d 条记录符合要求.\n",
                    Thread.currentThread().getName(), phaser.getPhase(), results.size());
            phaser.arriveAndAwaitAdvance(); // 通知Phaser对象当前线程已经完成了当前阶段，需要被阻塞直到其他线程也都完成当前阶段
            return true;
        }
    }

    /**
     * 打印结果集
     */
    private void showInfo() {
        for (int i = 0; i < results.size(); i++) {
            System.out.printf("%s : %s\n", Thread.currentThread().getName(), new File(results.get(i)).getAbsoluteFile());
        }
        phaser.arriveAndAwaitAdvance();
    }

    @Override
    public void run() {
        phaser.arriveAndAwaitAdvance(); // 等其他线程都初始化之后再一起执行，保障所有线程创建好之前没有线程开始执行任务
        System.out.printf("%s : 开始...\n", Thread.currentThread().getName());
        File file = new File(initPath);
        if (file.isDirectory()) {
            // 如果是目录就传入目录解析方法中
            directoryProcess(file);
        }
        // 检查结果集是否为空，为空就返回
        if (!checkResults()) {
            return;
        }
        // 进行文件过滤，将符合要求的文件的绝对路径放入results集合
        filterResults();
        // 检查过滤之后的结果集是否为空，为空就返回
        if (!checkResults()) {
            return;
        }
        // 打印结果集信息
        showInfo();
        phaser.arriveAndDeregister(); // 撤销在Phaser中线程的注册，当没有线程在Phaser中注册时，Phaser就会终止
        System.out.printf("%s : 工作完成.\n", Thread.currentThread().getName());
    }
}
